#define  _WIN32_WINNT   0x0500

#include "GUISys.h"
#include <process.h>
#include <ddraw.h>
#include <stdio.h>
#include <stdarg.h>
#include "..\game\MTVERIFY.h"
#include "..\ConfigGUI\global.h"


extern guiimport_t g_gui_imp;
extern void SetShooter(char*, date_ptr, TRAINMODEENUM);
extern void SetShooter2(TECHNIQUETYPE, double, unsigned int);

#define KO_THRDGUI		0
#define KO_EVENTQUIT	1
#define KO_ALL			2
static	HANDLE			g_hKernelObjs[KO_ALL];

static	DWORD				g_dwIdThrd;
#define MAINWNDCLASSNAME	TEXT("PredatorGUI")
#define MAINWNDCAPTION		TEXT("Predator")
static  char				g_szBitmap[] = "..\\Src\\resource\\GUISys\\background.bmp";
static	unsigned			WM_USER_QUIT_APP;
static  BOOL				g_bActive = FALSE;  // Is application active?
static  DWORD               g_dwUpdateDelay = 2000;

//-----------------------------------------------------------------------------
// Global data
//-----------------------------------------------------------------------------
LPDIRECTDRAW7               g_pDD = NULL;        // DirectDraw object
LPDIRECTDRAWSURFACE7        g_pDDSPrimary = NULL;// DirectDraw primary surface
LPDIRECTDRAWSURFACE7		g_pDDSBack = NULL;
LPDIRECTDRAWSURFACE7        g_pDDSOne = NULL;    // Offscreen surface 1
LPDIRECTDRAWCLIPPER         g_pClipper = NULL;   // Clipper for primary

LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ;

void ReleaseAllObjects(void)
{
    if (g_pDD != NULL)
    {
        if (g_pDDSPrimary != NULL)
        {
            IDirectDrawSurface7_Release(g_pDDSPrimary);
            g_pDDSPrimary = NULL;
        }
		if (g_pDDSBack != NULL)
		{
			IDirectDrawSurface7_Release(g_pDDSBack);
			g_pDDSBack = NULL;
		}
        if (g_pDDSOne != NULL)
        {
            IDirectDrawSurface7_Release(g_pDDSOne);
            g_pDDSOne = NULL;
        }
        IDirectDraw_Release(g_pDD);
        g_pDD = NULL;
    }
}

HRESULT InitFail(HWND hWnd, HRESULT hRet, LPCTSTR szError,...)
{
    char                        szBuff[128];
    va_list                     vl;

    va_start(vl, szError);
    vsprintf(szBuff, szError, vl);
    ReleaseAllObjects();
    MessageBox(hWnd, szBuff, "Error", MB_OK);
    DestroyWindow(hWnd);
    va_end(vl);
    return hRet;
}

HWND RenderMainWnd(HINSTANCE hInstance, HINSTANCE hPrevInstance,
						 PSTR szCmdLine, int iCmdShow)
{
     static TCHAR szAppName[] = MAINWNDCLASSNAME;
	 static TCHAR szWindowCaption[] = MAINWNDCAPTION;
     HWND         hwnd ;
     WNDCLASS     wndclass ;
	 HRESULT      hRet;
	 DDSURFACEDESC2 ddsd;
	 DWORD		  dwScreenWidth, dwScreenHeight;

     wndclass.style         = CS_HREDRAW | CS_VREDRAW ;
     wndclass.lpfnWndProc   = WndProc ;
     wndclass.cbClsExtra    = 0 ;
     wndclass.cbWndExtra    = 0 ;
     wndclass.hInstance     = hInstance ;
     wndclass.hIcon         = NULL ;
     wndclass.hCursor       = LoadCursor (NULL, IDC_ARROW) ;
     wndclass.hbrBackground = (HBRUSH) GetStockObject (BLACK_BRUSH) ;
     wndclass.lpszMenuName  = NULL ;
     wndclass.lpszClassName = szAppName ;

     if (!RegisterClass (&wndclass))
     {
          g_gui_imp.Sys_Error("This program requires Windows NT!") ;
          return NULL ;
     }
     hwnd = CreateWindow (szAppName,                  // window class name
                          szWindowCaption,			  // window caption
                          WS_OVERLAPPEDWINDOW,		  // window style
                          0,
                          0,
                          GetSystemMetrics(SM_CXSCREEN),
                          GetSystemMetrics(SM_CYSCREEN),
                          NULL,                       // parent window handle
                          NULL,                       // window menu handle
                          hInstance,                  // program instance handle
                          NULL) ;                     // creation parameters
     
     ShowWindow (hwnd, iCmdShow) ;
     UpdateWindow (hwnd) ;

	 ///////////////////////////////////////////////////////////////////////////
     // Create the main DirectDraw object
     ///////////////////////////////////////////////////////////////////////////
     hRet = DirectDrawCreateEx(NULL, (VOID**)&g_pDD, &IID_IDirectDraw7, NULL);
     if (hRet != DD_OK)
	 {
         InitFail(hwnd, hRet, "DirectDrawCreateEx FAILED");
		 goto _ret;
	 }

     // Get normal mode
     hRet = IDirectDraw_SetCooperativeLevel(g_pDD, hwnd, DDSCL_NORMAL);
     if (hRet != DD_OK)
	 {
         InitFail(hwnd, hRet, "SetCooperativeLevel FAILED");
		 goto _ret;
	 }

     // Create the primary surface
     ZeroMemory(&ddsd, sizeof(ddsd));
     ddsd.dwSize = sizeof(ddsd);
     ddsd.dwFlags = DDSD_CAPS;
     ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
     hRet = IDirectDraw_CreateSurface(g_pDD, &ddsd, &g_pDDSPrimary, NULL);
     if (hRet != DD_OK)
	 {
         InitFail(hwnd, hRet, "CreateSurface FAILED");
		 goto _ret;
	 }

     // Create a clipper for the primary surface
     hRet = IDirectDraw_CreateClipper(g_pDD, 0, &g_pClipper, NULL);
     if (hRet != DD_OK)
	 {
         InitFail(hwnd, hRet, "CreateClipper FAILED");
		 goto _ret;
	 }
     hRet = IDirectDrawClipper_SetHWnd(g_pClipper, 0, hwnd);
     if (hRet != DD_OK)
	 {
		 InitFail(hwnd, hRet, "SetHWnd FAILED");
		 goto _ret;
	 }
     hRet = IDirectDrawSurface7_SetClipper(g_pDDSPrimary, g_pClipper);
     if (hRet != DD_OK)
	 {
         InitFail(hwnd, hRet, "SetClipper FAILED");
		 goto _ret;
	 }

	 // Get the dimensions of the viewport and screen bounds
     dwScreenWidth = GetSystemMetrics(SM_CXSCREEN);
     dwScreenHeight = GetSystemMetrics(SM_CYSCREEN);

	 // Create a backbuffer
	 ddsd.dwFlags        = DDSD_WIDTH | DDSD_HEIGHT | DDSD_CAPS;
     ddsd.dwWidth        = dwScreenWidth;
     ddsd.dwHeight       = dwScreenHeight;
	 ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_3DDEVICE;

     if( FAILED( hRet = IDirectDraw_CreateSurface( g_pDD, &ddsd, &g_pDDSBack, NULL ) ) )
     {
         InitFail(hwnd, hRet, "Create back surface FAILED");
		 goto _ret;
     }

     // Load our bitmap
     g_pDDSOne = g_gui_imp.Load_Bitmap(g_pDD, g_szBitmap, 0, 0);
     if (g_pDDSOne == NULL)
	 {
         InitFail(hwnd, hRet, "DDLoadBitmap FAILED");
		 goto _ret;
	 }
     
_ret:
     return hwnd ;
}

BOOL RestoreAll(void)
{
    return IDirectDrawSurface7_Restore(g_pDDSPrimary) == DD_OK &&
		IDirectDrawSurface7_Restore(g_pDDSBack) == DD_OK &&
        IDirectDrawSurface7_Restore(g_pDDSOne) == DD_OK &&
        g_gui_imp.ReLoad_Bitmap(g_pDDSOne, g_szBitmap) == DD_OK;

}

void UpdateFrame(HWND hWnd)
{
	static DWORD                lastTickCount = 0;
	static int                  currentFrame = 0;
    DWORD                       thisTickCount;
    RECT                        rcRect = { 0, 0, 0, 0 };
    RECT                        destRect = { 0, 0, 0, 0 };
    HRESULT                     hRet;
	POINT						pt = { 0, 0 };

    thisTickCount = GetTickCount();
    if ((thisTickCount - lastTickCount) <= g_dwUpdateDelay)
		return;

	if (currentFrame++ > 59)
        currentFrame = 0;

    // Blit the stuff for the next frame
    rcRect.left = 0;
    rcRect.top = 0;
    rcRect.right = 1024;
    rcRect.bottom = 768;

	GetClientRect(hWnd, &destRect);
	pt.x = pt.y = 0;
	ClientToScreen(hWnd, &pt);
	OffsetRect(&destRect, pt.x, pt.y);

    while (TRUE)
    {
        hRet = IDirectDrawSurface7_Blt(g_pDDSBack, &destRect,
										g_pDDSOne, &rcRect, 0, NULL);

        if (hRet == DD_OK)
            break;
        if (hRet == DDERR_SURFACELOST)
        {
            if (!RestoreAll())
                return;
        }
        if (hRet != DDERR_WASSTILLDRAWING)
            return;
    }

    // Flip the surfaces
    while (TRUE)
    {
        hRet = IDirectDrawSurface7_Blt( g_pDDSPrimary, &destRect,
									g_pDDSBack, &destRect, DDBLT_WAIT,
									NULL );
        if (hRet == DD_OK)
            break;
        if (hRet == DDERR_SURFACELOST)
        {
            hRet = RestoreAll();
            if (hRet != DD_OK)
                break;
        }
        if (hRet != DDERR_WASSTILLDRAWING)
            break;
    }
}

LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	 DDBLTFX                     ddbltfx;
	 
	 switch (message)
     {
	 case WM_ACTIVATE:
          // Pause if minimized
          g_bActive = !((BOOL)HIWORD(wParam));
          return 0L;

	 case WM_ERASEBKGND:
		  // Use the blter to do a color fill to clear the front buffer
		  if (NULL != g_pDDSBack && NULL != g_pDDSPrimary)
		  {
			HDC	hDC = (HDC)wParam;
			RECT rcClient, rcWindow;
			POINT pt;
			int rtn = GetClipBox(hDC, &rcClient);
			
			GetClientRect(hwnd, &rcWindow);
			pt.x = pt.y = 0;
			ClientToScreen(hwnd, &pt);
			OffsetRect(&rcClient, pt.x, pt.y);
			OffsetRect(&rcWindow, pt.x, pt.y);
			
			if (2 * (rcClient.bottom - rcClient.top) >
				rcWindow.bottom - rcWindow.top)
			{
				// Use the blter to do a color fill to clear the back buffer
				ZeroMemory(&ddbltfx, sizeof(ddbltfx));
				ddbltfx.dwSize = sizeof(ddbltfx);
				ddbltfx.dwFillColor = 0;
				IDirectDrawSurface7_Blt(g_pDDSBack, NULL, NULL, NULL,
										DDBLT_COLORFILL | DDBLT_WAIT,
										&ddbltfx);
				IDirectDrawSurface7_Blt(g_pDDSPrimary, &rcWindow,
										g_pDDSBack, &rcWindow,
										DDBLT_WAIT, NULL);
			}
		  }
		  break;

	 case WM_SYSCOMMAND:
		  if (SC_CLOSE == wParam)
		  {
			SetEvent(g_hKernelObjs[KO_EVENTQUIT]);
			/* end displaying the main frame dialog */
			Destroy_Dialog();
			return 0;
		  }
		  break;

	 case WM_CLOSE:
		  DestroyWindow(hwnd);
		  return 0;

	 case WM_DESTROY:
		  ReleaseAllObjects();
		  PostQuitMessage(0);
		  return 0;
     }
     return DefWindowProc (hwnd, message, wParam, lParam) ;
}

DWORD ChildInit(HWND* phWnd, RECT rect)
{
	Init_Config_GUI(g_gui_imp, SetShooter, SetShooter2);
	*phWnd = Init_Dialog(rect);

	if (NULL == *phWnd)
	{
		fprintf(stderr, "Error when init child dialog.\n");
		return -1;
	}

	return 0;
}

DWORD WINAPI GUIInit(void* datain)
{
	MSG		msg;
	RECT	rect;
	HWND	hWnd, hWndChild = NULL;
	DWORD	status = -1;

	/* not using parameter */
	(void)datain;

	/* register a user defined message to notify a closing event */
	WM_USER_QUIT_APP = RegisterWindowMessage("End threads and exit.");

	hWnd =  RenderMainWnd(g_gui_imp.global_hInstance, NULL, NULL, SW_SHOWNORMAL);
	
	if (NULL == hWnd)
	{
		fprintf(stderr, "Error when render main GUI window.\n");
		return -1;
	}

	/* get client rect */
	GetClientRect(hWnd, &rect);

	/* begin displaying main frame dialog */
	if (-1 == (status = ChildInit(&hWndChild, rect))) return status;

	while (TRUE)
	{
		if (PeekMessage (&msg, NULL, 0, 0, PM_NOREMOVE))
		{
			if (!GetMessage(&msg, NULL, 0, 0))
				break;
			if (msg.hwnd != NULL && msg.hwnd != hWnd)
			{
				Pre_Trans_Dlg_Msgs(msg.hwnd, &msg);
				DispatchMessage (&msg);
			}
			else if (WM_USER_QUIT_APP == msg.message)
			{
				DestroyWindow(hWnd);
				break;
			}
			else
			{
				TranslateMessage(&msg);
				DispatchMessage (&msg);
			}
		}
		else if (g_bActive)
        {
            UpdateFrame(hWnd);
        }
		Sleep(10);
	}

    return (msg.wParam);
}

pboolean PreGUIInit(void)
{
	DWORD result;

	MTVERIFY(g_hKernelObjs[KO_THRDGUI] =
		(HANDLE)_beginthreadex(	
			NULL,		/* security level */ 
			0,			/* stack size */
			GUIInit,	/* starting address of thread procedure */
			NULL,		/* parameter list */
			0,			/* init flag */
			&g_dwIdThrd));	/* thread handle */

	g_hKernelObjs[KO_EVENTQUIT] =
		CreateEvent(NULL, FALSE, FALSE, NULL);

	while (TRUE)
	{
		result = WaitForMultipleObjects(KO_ALL, g_hKernelObjs,
										   FALSE, INFINITE);

		switch (result - WAIT_OBJECT_0)
		{
		case KO_THRDGUI:
			MTVERIFY(CloseHandle(g_hKernelObjs[KO_THRDGUI]));
			return true;

		case KO_EVENTQUIT:
			PostThreadMessage(g_dwIdThrd, WM_USER_QUIT_APP, 0, 0);
			return false;

		default:
			break;
		}
	}

	return true;
}

